import java.util.Comparator;
public class osobnik {
private przedzial range;
private	double fhromosome;
private	int ihromosome;
private double functionValue;
private double accommodationValue;
private double expectedOffspringNumber;
/**
 * Tworzy nowego osobnika z wartosci zmiennoprzecinkowej
 * 
 * @param range przedzial do ktorego moga nalezec osobniki
 * @param fhromosome wartosc osobnika
 */
public osobnik(przedzial range,double fhromosome){
	this.range = range;
	this.fhromosome = fhromosome;
	this.functionValue = function.retFunc(this.fhromosome);
	this.ihromosome = this.range.toBitVec(fhromosome);
}
/**
 *  Tworzy nowego osobnika z jego kodu bitowego
 * @param range set output 'output/dijkstraGL.png'
 * @param ihromosome kod bitowy osobnika
 */
public osobnik(przedzial range,int ihromosome){
	this.range = range;
	this.ihromosome = Math.abs(ihromosome);
	this.fhromosome = this.range.bitVecToFloat(ihromosome);
	this.functionValue = function.retFunc(this.fhromosome);
}
/**
 * Konstruktor kopiujacy
 * @param obj
 */
public osobnik(osobnik obj){
	this.range = obj.range;
	this.fhromosome = obj.fhromosome;
	this.ihromosome = obj.ihromosome;
	this.functionValue = obj.functionValue;
	this.accommodationValue = obj.accommodationValue;
	this.expectedOffspringNumber = obj.expectedOffspringNumber;
	
}
/**
 * Krzyzuje osobnika z innym
 * Wykorzystuje krzyzowanie dwupunktowe
 * @param b osobnik do krzyzowania
 * @return tablica 6 potomkow
 */
public  osobnik[] crossover( osobnik b){
	int N=6;
	int intResult[] = new int[N];
	int x,y;
	int delta = 16;
	x=(int) (Math.random()*(this.range.bits - 2 -1)) + 1;
	do{
		y=(int) (Math.random()*(this.range.bits - 2 -1)) + 1;
	}while(x == y);
	
	if(x<y){
		int tmp;
		tmp = x;
		x = y;
		y =tmp;
	}
	int fragments[][] = new int[2][3];

	int masks[] = new int[3];
	
	masks[0] = (int)Math.pow(2, y) -1;
	fragments[0][0] = this.ihromosome & masks[0];
	fragments[1][0] = b.ihromosome & masks[0];
	
	masks[1] = ((int)Math.pow(2, x-y) -1) << y;
	fragments[0][1] = this.ihromosome & masks[1];
	fragments[1][1] = b.ihromosome & masks[1];
	
	masks[2] = (~(masks[0] | masks[1])) & Integer.MAX_VALUE;

	
	fragments[0][2] = this.ihromosome & masks[2];
	fragments[1][2] = b.ihromosome & masks[2];
	
	int bmask=1;
	int res;
	for(int i=1;i<=6;i++){
		for(int j = 0;j<3;j++){
			res = i & (bmask<<j);
			if(res > 0 ){
				intResult[i-1]|=fragments[1][j];
			}
			else{
				intResult[i-1]|=fragments[0][j];
			}
				
		}
	}
//	for( int i =0; i<N;i++){
//		System.out.printf("%x\n", intResult[i]);
//	}
	osobnik[] result = new osobnik[N];
	for(int i = 0; i <result.length;i++){
		result[i] = new osobnik(this.range,intResult[i]);
	}
	
	return result;
}
/**
 * Mutuje osobnika
 * Wymienia losowy bit na przeciwny
 */
public void mutate(double probability){
	int mask = 1;
	for(int i=0;i<this.range.bits;i++){
		if(probability > Math.random()){
			this.ihromosome^=mask;
		}
		mask = mask<<1;
	}
	
	
	
	//System.out.println("F:" + this.fhromosome +"F(I)" + this.range.bitVecToFloat(this.ihromosome));
	this.fhromosome = this.range.bitVecToFloat(ihromosome);
	this.functionValue = function.retFunc(this.fhromosome);
}

public double getFunctionValue() {
	return this.functionValue;
}
public double getAccommodationValue() {
	return this.accommodationValue;
}
public void setAccommodationValue(double accommodationValue) {
	this.accommodationValue = accommodationValue;
}
public double getExpectedOffspringNumber() {
	return this.expectedOffspringNumber;
}
public int getExpectedOffspringNumberInt() {
	return (int)(this.expectedOffspringNumber);
}
public double getExpectedOffspringNumberFraction() {
	return this.expectedOffspringNumber - (int)(this.expectedOffspringNumber);
}
public void setExpectedOffspringNumber(double expectedOffspringNumber) {
	this.expectedOffspringNumber = expectedOffspringNumber;
}
public double getFhromosome() {
	return this.fhromosome;
}
public int getIhromosome() {
	return this.ihromosome;
}


@Override
public int hashCode() {
	final int prime = 31;
	int result = 1;
	result = prime * result + ihromosome;
	return result;
}
@Override
public boolean equals(Object obj) {
	if (this == obj)
		return true;
	if (obj == null)
		return false;
	if (getClass() != obj.getClass())
		return false;
	osobnik other = (osobnik) obj;
	if (ihromosome != other.ihromosome)
		return false;
	return true;
}



@Override
public String toString() {
	return "osobnik [fhromosome=" + fhromosome + ", functionValue="
			+ functionValue +", expectedOffspringNumber =" +this.expectedOffspringNumber +
			",  accommodationValue=" +this.accommodationValue + "]";
}


/**
 * 
 * Komparator porownuje osobniki ze wzgledu na calkowita wartosc
 * oczekiwanej ilosci potomstwa
 *
 */
static class offspringIntSort implements Comparator<osobnik>{

	@Override
	public int compare(osobnik o1, osobnik o2) {
		return - Double.compare(o1.expectedOffspringNumber, o2.expectedOffspringNumber);
	}
	
}
static Comparator<osobnik> OffspringIntSort = new offspringIntSort();

/**
 * 
 * Komparator porownuje osobniki ze wzgledu na ulamkowa wartosc
 * oczekiwanej ilosci potomstwa
 *
 */
static class offspringFractionSort implements Comparator<osobnik>{

	@Override
	public int compare(osobnik o1, osobnik o2) {
		double o1f,o2f;
		int o1i,o2i;
		o1i = (int)Math.floor(o1.expectedOffspringNumber);
		o2i = (int)Math.floor(o2.expectedOffspringNumber);
		o1f = o1.expectedOffspringNumber - o1i;
		o2f = o2.expectedOffspringNumber - o2i;
		if(o1f < o2f)return 1;
		if(o1f > o2f)return -1;
		return 0;
	}
	
}
static Comparator<osobnik> OffspringFractionSort = new offspringFractionSort();
static class offspringRandSort implements Comparator<osobnik>{

	@Override
	public int compare(osobnik o1, osobnik o2) {
	
		if(Math.random() < 0.5){
			return 1;
		}
		return -1;
	}
	
}
static Comparator<osobnik> OffspringRandSort = new offspringRandSort();

}
